/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file  desc_op.c
 * @brief Semidrive. AUTOSAR 4.3.1 MCAL Eth plugins.
 */
#ifdef __cplusplus
extern "C" {
#endif

// dmb need
#include "descs.h"
#include "Eth_Fault.h"
#include "Eth_PBCfg.h"
#include "Mcal.h"
#include "Mcal_Cache.h"

#define  ETH_DEBUG(...)

#define ETH_START_SEC_CODE_FAST
#include "Eth_MemMap.h"

/**
 * @brief Retrieves the transmit status of a DMA descriptor.
 *
 * This function examines the contents of the third descriptor field (TDES3) of a DMA descriptor to determine
 * the status of the transmit operation associated with that descriptor. It checks for ownership, last segment
 * flag, and error summary to determine the transmit status.
 *
 * @param d Pointer to the DMA descriptor structure.
 *
 * @return An enum value indicating the transmit status. Possible values include:
 *   - TX_GOOD: The transmit operation completed successfully.
 *   - TX_DMA_PROCESS: The transmit operation is still being processed by the DMA.
 *   - TX_NOT_LS: The descriptor is not marked as the last segment of a frame.
 *   - TX_ERROR: An error occurred during the transmit operation.
 *
 * @note This function assumes that the necessary constants (e.g., DES3_OWN, DES3_LAST_DESCRIPTOR, TDES3_ERR_SUMMARY)
 *       and the DMA descriptor structure (`struct dma_desc`) are defined and available for use. It also calls an
 *       external function `EthFaultInj_Eth_Desc_Test()` for optional fault injection testing, which is not defined
 *       in the provided code snippet.
 */
enum tx_frame_status dwmac_wrback_get_tx_status(struct dma_desc *d)
{

    uint32 tdes3;
    enum tx_frame_status ret = TX_GOOD;
    EthFaultInj_Eth_Desc_Test();
    tdes3 = (d->des3);

    /* Get tx owner first */
    if ((tdes3 & DES3_OWN)){
        ret =  TX_DMA_PROCESS;
    }else{
        /* Verify tx error by looking at the last segment. */
        if ((!(tdes3 & DES3_LAST_DESCRIPTOR)))
            ret =  TX_NOT_LS;

        if ((tdes3 & TDES3_ERR_SUMMARY)) {
            ret = TX_ERROR;
        }
    }
    return ret;
}

/**
 * @brief Retrieves the receive status of a DMA descriptor.
 *
 * This function examines the contents of the third descriptor field (RDES3) of
 * a DMA descriptor to determine
 * the status of the receive operation associated with that descriptor.
 * It checks for ownership, last segment
 * flag, and error summary to determine the receive status. Additionally,
 * when debugging is enabled, it checks
 * the PTP-related fields in the descriptor to provide additional information
 * about the received packet.
 *
 * @param d Pointer to the DMA descriptor structure.
 *
 * @return An enum value indicating the receive status. Possible values include:
 *   - RX_GOOD: The receive operation completed successfully.
 *   - RX_DMA_PROCESS: The receive operation is still being processed by the DMA.
 *   - RX_BAD: An error occurred during the receive operation or the descriptor
 *      is not marked as the last segment.
 *
 * @note This function assumes that the necessary constants (e.g., DES3_OWN,
 *       DES3_LAST_DESCRIPTOR, RDES3_ERR_SUMMARY,
 *       DES3_FIRST_DESCRIPTOR, DES3_CONTEXT_TYPE, ERDES4_MSG_TYPE_MASK)
 *       and the DMA descriptor structure
 *       (`struct dma_desc`) are defined and available for use. It also
 *       relies on external functions
 *       `EthFaultInj_Eth_Desc_Test_Rx()` for optional fault injection
 *       testing and `ETH_DEBUG()` for debugging
 *       messages, which are not defined in the provided code snippet.
 *       The debug-related checks and messages
 *       are conditionally compiled based on the `ENABLE_ETH_DBG` macro.
 */
enum rx_frame_status dwmac_wrback_get_rx_status(struct dma_desc *d)
{
    EthFaultInj_Eth_Desc_Test_Rx();

    uint32 rdes3 = (d->des3);
#if defined(ENABLE_ETH_DBG)
    sint32 message_type;
#endif
    enum rx_frame_status ret = RX_GOOD;

    if ((rdes3 & DES3_OWN))
    {
        ret =  RX_DMA_PROCESS;
    }
    else
    {

        /* Verify rx error by looking at the last segment. */
        if ((!(rdes3 & DES3_LAST_DESCRIPTOR))) {
            ret =  RX_BAD;
        }
        if ((rdes3 & RDES3_ERR_SUMMARY) ||
            ((DES3_FIRST_DESCRIPTOR|DES3_CONTEXT_TYPE) ==
            (rdes3 & (DES3_FIRST_DESCRIPTOR|DES3_CONTEXT_TYPE)))) {
            ret = RX_BAD;
        }
#if defined(ENABLE_ETH_DBG)
        /*
            not check PFT bit because this bit
            availd only when timestamp is enabled
        */
        message_type = (rdes1 & ERDES4_MSG_TYPE_MASK) >> 8;
        if (message_type == RDES_EXT_NO_PTP) {
            /* no_ptp_rx_msg_type_ext */
            ETH_DEBUG("Is not ptp pac\n");
        } else {
            if (message_type == RDES_EXT_SYNC) {
                /* ptp_rx_msg_type_sync */
                ETH_DEBUG("ptp sync\n");
            } else if (message_type == RDES_EXT_FOLLOW_UP) {
                /* ptp_rx_msg_type_follow_up */
                ETH_DEBUG("ptp follow_up\n");
            } else if (message_type == RDES_EXT_DELAY_REQ) {
                /* ptp_rx_msg_type_delay_req */
                ETH_DEBUG("ptp delay_req\n");
            } else if (message_type == RDES_EXT_DELAY_RESP) {
                ETH_DEBUG("ptp delay_resp\n");
                /* ptp_rx_msg_type_delay_resp */
            } else if (message_type == RDES_EXT_PDELAY_REQ) {
                /* ptp_rx_msg_type_pdelay_req */
                ETH_DEBUG("ptp pdelay_req\n");
            } else if (message_type == RDES_EXT_PDELAY_RESP) {
                /* ptp_rx_msg_type_pdelay_resp */
                ETH_DEBUG("ptp pdelay_resp\n");
            } else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP) {
                /* ptp_rx_msg_type_pdelay_follow_up */
                ETH_DEBUG("ptp pdelay_follow_up\n");
            } else if (message_type == RDES_PTP_ANNOUNCE) {
                /* ptp_rx_msg_type_announce */
                ETH_DEBUG("ptp announce\n");
            } else if (message_type == RDES_PTP_MANAGEMENT) {
                /* ptp_rx_msg_type_management */
                ETH_DEBUG("ptp management\n");
            } else if (message_type == RDES_PTP_PKT_RESERVED_TYPE) {
                /* ptp_rx_msg_pkt_reserved_type */
                ETH_DEBUG("ptp reserved_type\n");
            }

            /* ptp_frame_type */
            if (rdes1 & RDES1_PTP_PKT_TYPE) {
                ETH_DEBUG("PTP_L2\n");
            } else {
                ETH_DEBUG("PTP_L4\n");
            }

            /* ptp_ver */
            if (rdes1 & RDES1_PTP_VERSION) {
                ETH_DEBUG("PTP_V2\n");
            } else {
                ETH_DEBUG("PTP_V1\n");
            }
        }
#endif
    }
    return ret;
}

/**
 * @brief Sets the receive ownership and interrupt-on-completion flag of a DMA descriptor.
 *
 * This function configures the given DMA descriptor for receive operations by setting
 * the ownership bit and, optionally, enabling interrupts on completion.
 *
 * @param p Pointer to the DMA descriptor structure.
 * @param enable_rx_ic Enable or disable interrupts on completion. If true, enables interrupts.
 *                     If false, disables interrupts.
 *
 * @note This function modifies the des3 field of the DMA descriptor to set the ownership
 * and interrupt-on-completion flags according to the provided parameters.
 */
void dwmac_set_rx_owner(struct dma_desc *p, uint32 enable_rx_ic)
{
    p->des3 = (DES3_OWN | RDES3_BUFFER1_ADDR_VALID);

    if (enable_rx_ic)
        p->des3 |= (RDES3_INT_EN_ON_COMPLETION);
}

/**
 * @brief Retrieves the length of the received frame from a DMA descriptor.
 *
 * This function extracts the packet size from the des3 field of the given DMA descriptor
 * and returns it as a 16-bit unsigned integer.
 *
 * @param p Pointer to the DMA descriptor structure.
 * @return The length of the received frame, as stored in the DMA descriptor.
 *
 * @note The length is extracted by masking the des3 field with the RDES3_PACKET_LEN_MASK.
 */
uint16 dwmac_wrback_get_rx_frame_len(struct dma_desc *p)
{
    return (uint16)((p->des3) & RDES3_PACKET_LEN_MASK);
}

/**
 * @brief Retrieves the transmit timestamp status from a DMA descriptor.
 *
 * This function checks the given DMA descriptor to determine if transmit timestamping
 * is applicable (by verifying that the context type is zero) and if a valid timestamp
 * has been captured (by checking the timestamp status bit).
 *
 * @param p Pointer to the DMA descriptor structure.
 * @return A signed 32-bit integer indicating the timestamp status.
 *         - 1: Transmit timestamping is enabled and a valid timestamp is available.
 *         - 0: Transmit timestamping is not applicable or no valid timestamp is available.
 *
 * @note This function assumes that the DMA descriptor has been written back and is
 * no longer owned by the DMA engine. Additionally, it does not retrieve the actual
 * timestamp value; it only checks the status of timestamping.
 */
sint32 dwmac_wrback_get_tx_timestamp_status(struct dma_desc *p)
{
    /* Context type from W/B descriptor must be zero */
    if ((p->des3) & DES3_CONTEXT_TYPE)
        return 0;

    /* Tx Timestamp Status is 1 so des0 and des1'll have valid values */
    if ((p->des3) & TDES3_TS_STATUS)
        return 1;

    return 0;
}

/**
 * @brief Checks if a valid receive timestamp is available in a DMA descriptor.
 *
 * This function examines a DMA descriptor for receive operations to determine if
 * a valid timestamp is ready to be read. It first checks if the descriptor is owned
 * by the DMA engine (DES3_OWN bit), then checks if the descriptor is a context
 * descriptor (DES3_CONTEXT_TYPE bit). If it is a context descriptor, it
 * further checks the des0 and des1 fields for valid timestamp values.
 *
 * @param d Pointer to the DMA descriptor structure for the receive operation.
 * @return A signed 32-bit integer indicating the timestamp status.
 *         -1: Descriptor is still owned by the DMA engine.
 *          0: No valid timestamp available or descriptor is corrupted.
 *          1: A valid timestamp is ready to be read.
 */
static sint32 dwmac_rx_check_timestamp(struct dma_desc *d)
{
    sint32 ret = 0;
    EthFaultInj_Eth_DescOwn_Test();
    if (d->des3 & DES3_OWN)
        return -1;

    if (d->des3 & DES3_CONTEXT_TYPE) {
        EthFaultInj_Eth_rxDesc_Test();
        if (d->des0 == 0xffffffff) {
            /* Corrupted value */
            ret = 2;
        } else {
            /* A valid Timestamp is ready to be read */
            ret = 1;
        }
    }

    return ret;
}
/**
 * @description:
 * @param {dma_desc} *d
 * @param {dma_desc} *next_d
 * @return {*} 1 timestamp ok
               0 not timestamp
               2 timestamp illegal
 */
uint32 dwmac_wrback_get_rx_timestamp_status(struct dma_desc *d, struct dma_desc *next_d)
{
    uint8 i = 0;
    sint32 ret = 0;
    ETH_DEBUG("2dp %d desc %08x desc %08x desc %08x desc %08x\n", d, d->des0, d->des1, d->des2,
              d->des3);

    /* Get the status from normal w/b descriptor */
    if (((d->des3 & (DES3_LAST_DESCRIPTOR | RDES3_RS1V)) ==
         (DES3_LAST_DESCRIPTOR | RDES3_RS1V)) && 
        ((d->des1) & RDES1_TS_AVAIL) ) {
        /* Check if timestamp is OK from context descriptor */
        do {
            ret = dwmac_rx_check_timestamp(next_d);
            i++;
#if (ETH_NO_CACHEABLE_NEEDED == STD_OFF)
            Mcal_InvalidateCache((uint32)next_d,CACHE_LINE);
#endif
        } while ((ret == -1) && (i < 10u));

        if (i >= 10u){
            ret = -2;
        }
    }

    if ((ret < 0)){
        ret = 0;
    }

    return (uint32)ret;
}

/**
 * @brief Initializes a receive DMA descriptor.
 *
 * This function initializes a DMA descriptor for receive operations, setting the
 * ownership and enabling/disabling receive interrupt coalescing as specified.
 *
 * @param p Pointer to the DMA descriptor structure to be initialized.
 * @param enable_rx_ic Boolean indicating whether to enable receive interrupt coalescing.
 *                     A non-zero value enables RX IC, while zero disables it.
 *
 * @note This function assumes that the DMA descriptor is not currently owned by the DMA engine.
 */
void dwmac_rd_init_rx_desc(struct dma_desc *p, uint32 enable_rx_ic)
{
    dwmac_set_rx_owner(p, enable_rx_ic);
}

/**
 * @brief Initializes a transmit DMA descriptor.
 *
 * This function initializes a DMA descriptor for transmit operations by resetting
 * all its fields to zero.
 *
 * @param p Pointer to the DMA descriptor structure to be initialized.
 *
 * @note This function prepares the DMA descriptor for use in transmit operations
 * by clearing its contents. It does not set the ownership bit or configure any
 * specific transmit parameters.
 */
void dwmac_rd_init_tx_desc(struct dma_desc *p)
{
    p->des0 = 0;
    p->des1 = 0;
    p->des2 = 0;
    p->des3 = 0;
}

/**
 * @brief Prepares a transmit DMA descriptor for transmission.
 *
 * This function initializes and configures a DMA descriptor for transmit operations,
 * setting the buffer size, packet length, flags, and other relevant parameters.
 *
 * @param p Pointer to the DMA descriptor structure to be prepared.
 * @param len The size of the data buffer pointed to by this descriptor.
 * @param tot_pkt_len The total length of the packet being transmitted.
 * @param flags A combination of flags that specify additional configuration options.
 *              Valid flags include:
 *              - DESC_FLAGS_TX_FIRST: Indicates this is the first descriptor in a chain.
 *              - DESC_FLAGS_TX_CPC_CRC_INSER: Enables CRC insertion.
 *              - DESC_FLAGS_TX_CPC_PAD_INSER: Enables padding insertion.
 *              - DESC_FLAGS_TX_CPC_CRC_REPLA: Enables CRC replacement.
 *              - DESC_FLAGS_TX_SAIC_REPLA: Enables source address insertion or replacement.
 *              - DESC_FLAGS_TX_CHK_SHIFT: Specifies checksum insertion options.
 *              - DESC_FLAGS_TX_LAST: Indicates this is the last descriptor in a chain.
 *              - DESC_FLAGS_TX_OWN: Sets the ownership bit to grant control to the DMA engine.
 *              - DESC_FLAGS_IC: Enables interrupt coalescing.
 *              - DESC_FLAGS_TIMESTAMP: Enables transmit timestamping.
 *
 * @note The DESC_FLAGS_TX_OWN flag must be set to grant ownership of the descriptor to the DMA engine.
 *       If DESC_FLAGS_TX_FIRST and DESC_FLAGS_TX_OWN are both set, a dmb() is called to ensure
 *       that all writes to the descriptor are completed before the DMA engine accesses it.
 */
void dwmac_rd_prepare_tx_desc(struct dma_desc *p, uint32 len,
                              uint32 tot_pkt_len, uint32 flags)
{
    uint32 tdes3 = (p->des3);

    p->des2 |= (len & TDES2_BUFFER1_LEN_MASK);

    if (flags & DESC_FLAGS_IC) {
        p->des2 |= (TDES2_INT_ON_COMP);
    }

    if (flags & DESC_FLAGS_TIMESTAMP) {
        p->des2 |= (TDES2_TTSP_WMWD);
    }

    tdes3 |= tot_pkt_len & TDES3_FRAME_LEN_MASK;

    tdes3 |= DES3_FIRST_DESCRIPTOR | DES3_LAST_DESCRIPTOR;

    if (!(flags & DESC_FLAGS_TX_CPC_PAD_INSER) &&
        (flags & DESC_FLAGS_TX_SAIC_REPLA)) {
        tdes3 |= TDES3_SA_REPLACE_DESCRIPTOR;
    }

#ifdef CHECKSUM_INSERTION_CONFIG
    /*PRQA S 2880  6*/
    if (CHECKSUM_INSERTION_CONFIG != TDES3_CKSUM_INS_DISABLE)
    {
        tdes3 &= ~TDES3_CKSUM_INS_MASK;
        tdes3 |= CHECKSUM_INSERTION_CONFIG;
        tdes3 &= ~TDES3_TCP_SEG_ENABLE;
    }
#endif

    /* Finally set the OWN bit. Later the DMA will start! */
    tdes3 |= DES3_OWN;
    /* Finally set the OWN bit. Later the DMA will start! */
    p->des3 = tdes3;

    if ((flags & DESC_FLAGS_TX_FIRST) && (flags & DESC_FLAGS_TX_OWN))
        ASM_KEYWORD("dmb sy");
}

/**
 * @brief Sets the buffer address in a DMA descriptor.
 *
 * This function sets the buffer address field in the specified DMA descriptor to the
 * provided address. This address points to the data buffer that will be transmitted
 * or received by the DMA engine.
 *
 * @param p Pointer to the DMA descriptor to be configured.
 * @param addr Pointer to the buffer address to be set in the DMA descriptor.
 *
 * @note The provided address should be aligned according to the DMA engine's requirements.
 */
void dwmac_set_addr(struct dma_desc *p, uint32 *addr)
{
    p->des0 = (uint32)addr;
}

/**
 * @brief Clears a DMA descriptor.
 *
 * This function resets all fields of the specified DMA descriptor to zero. This operation
 * prepares the descriptor for reuse or initialization with new values.
 *
 * @param p Pointer to the DMA descriptor to be cleared.
 */
void dwmac_clear(struct dma_desc *p)
{
    p->des0 = 0;
    p->des1 = 0;
    p->des2 = 0;
    p->des3 = 0;
}

#define ETH_STOP_SEC_CODE_FAST
#include "Eth_MemMap.h"

#ifdef __cplusplus
}
#endif
